#ifndef _VECTOR4_HPP_
#define _VECTOR4_HPP_

#include "Vector3.hpp"

#include "Vector2.hpp"

class Vector4 {
public:

	union {
	
		struct {
		
			float x;
			
			float y;
			
			float z;
			
			float w;
		
		};
		
		struct {
			
			float r;
			
			float g;
			
			float b;
			
			float a;
			
		};
		
	};
	
public:

	float* getPtr() {
		return (float*)this;
	}

	const float* getPtr() const {
		return (float*)this;
	}
	
	operator Vector2 () {
		return Vector2(x * w, y * y);
	}

	Vector2 toVector2() const {
		return Vector2(x * w, y * w);
	}
	
	operator Vector3 () {
		return Vector3(x * w, y * w, z * w);
	}
	
	Vector3 toVector3() const {
		return Vector3(x * w, y * w, z * w);
	}
	
	float& operator[] (unsigned int index) {
		return ((float*)this)[index];
	}
	
	Vector4 operator + (const Vector4& v) const {
		return Vector4(x + v.x, y + v.y, z + v.z, w + v.w);
	}
	
	Vector4 operator - (const Vector4& v) const {
		return Vector4(x - v.x, y - v.y, z - v.z, w - v.w);
	}

	Vector4 operator * (const Vector4& v) const {
		return Vector4(x * v.x, y * v.y, z * v.z, w * v.w);
	}

	Vector4 operator / (const Vector4& v) const {
		return Vector4(x / v.x, y / v.y, z / v.z, w / v.w);
	}
	
	void operator += (const Vector4& v) {
		x += v.x;
		y += v.y;
		z += v.z;
		w += v.w;
	}
	
	void operator -= (const Vector4& v) {
		x -= v.x;
		y -= v.y;
		z -= v.z;
		w -= v.w;
	}

	void operator *= (const Vector4& v) {
		x *= v.x;
		y *= v.y;
		z *= v.z;
		w *= v.w;
	}
	
	void operator /= (const Vector4& v) {
		x /= v.x;
		y /= v.y;
		z /= v.z;
		w /= v.w;
	}
	
	Vector4 operator + (float s) const {
		return Vector4(x + s, y + s, z + s, w + s);
	}
	
	Vector4 operator - (float s) const {
		return Vector4(x - s, y - s, z - s, w - s);
	}
	
	Vector4 operator * (float s) const {
		return Vector4(x * s, y * s, z * s, w * s);
	}
	
	Vector4 operator / (float s) const {
		return Vector4(x / s, y / s, z / s, w / s);
	}
	
	void operator += (float s) {
		x += s;
		y += s;
		z += s;
		w += s;
	}
	
	void operator -= (float s) {
		x -= s;
		y -= s;
		z -= s;
		w -= s;
	}
	
	void operator *= (float s) {
		x *= s;
		y *= s;
		z *= s;
		w *= s;
	}

	void operator /= (float s) {
		x /= s;
		y /= s;
		z /= s;
		w /= s;
	}
	
public:

	/*
		Длинна вектора
	*/

	float length() const {
		return sqrt(x * x + y * y + z * z + w * w);
	}
	
	/*
		Длинна вектора
	*/

	static float length(const Vector4& v) {
		return v.length();
	}
	
	/*
		Расстояние между двумя векторами
	*/
	
	static float distance(const Vector4& v1, const Vector4& v2) {
		return (v2 - v1).length();
	}
	
	/*
		Скалярное произведение (dot product)
	*/
	
	static float dot(const Vector4& v1, const Vector4& v2) {
		return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
	}
	
	/*
		Нормализация
	*/
	
	static Vector4 normalize(const Vector4& v) {
		return v * (1.0f / v.length());
	}

	/*
		Линейная интерполяция
	*/
	
	static Vector4 lerp(const Vector4& v1, const Vector4& v2, float a) {
		return Vector4(
			(v2.x - v1.x) * a + v1.x,
			(v2.y - v1.y) * a + v1.y,
			(v2.z - v1.z) * a + v1.z,
			(v2.w - v1.w) * a + v1.w
		);
	}
	
public:

	Vector4(const Vector2& v1, const Vector2& v2) {
		Vector4::x = v1.x;
		Vector4::y = v1.y;
		Vector4::z = v2.x;
		Vector4::w = v2.y;
	}

	Vector4(float x, float y, const Vector2& v) {
		Vector4::x = x;
		Vector4::y = y;
		Vector4::z = v.x;
		Vector4::w = v.y;
	}

	Vector4(float x, const Vector2& v, float w = 1.0f) {
		Vector4::x = x;
		Vector4::y = v.x;
		Vector4::z = v.y;
		Vector4::w = w;
	}

	Vector4(const Vector2& v, float z = 0.0f, float w = 1.0f) {
		Vector4::x = v.x;
		Vector4::y = v.y;
		Vector4::z = z;
		Vector4::w = w;
	}

	Vector4(float x, const Vector3& v) {
		Vector4::x = x;
		Vector4::y = v.x;
		Vector4::z = v.y;
		Vector4::w = v.z;
	}
	
	Vector4(const Vector3& v, float w = 1.0f) {
		Vector4::x = v.x;
		Vector4::y = v.y;
		Vector4::z = v.z;
		Vector4::w = w;
	}

	Vector4(float s) {
		Vector4::x = s;
		Vector4::y = s;
		Vector4::z = s;
		Vector4::w = s;
	}

	Vector4(float x, float y, float z = 0.0f, float w = 1.0f) {
		Vector4::x = x;
		Vector4::y = y;
		Vector4::z = z;
		Vector4::w = w;
	}

	Vector4() {
	}
	
};

#endif